home *** CD-ROM | disk | FTP | other *** search
- #ifndef THINK_C
- #include <QuickDraw.h>
- #include <OSUtils.h>
- #include <ThreadUtil.h>
- #endif
-
- #include "ProtoStructs.h"
- #include "Globals.h"
-
- /* Text replacement keeps me sane */
- #define RIGHT_FORK(thisOne) gForks[((thisOne->left_fork + 1) % kNumOfPhilosophizers)]
- #define LEFT_FORK(thisOne) gForks[thisOne->left_fork]
-
-
- /*
- ** If you want to play around and see the effects of using an ArraySemaphore for
- ** the footman, just uncomment the line below and check out how the Philosophizers
- ** are let in the room.
- **
- ** #define kUsingArraySemaphore TRUE
- */
-
- #ifdef kUsingArraySemaphore
- ArraySemaphorePtr gFootman;
- #else
- short gNumEating;
- #endif
- /***********************************************************************************
- ****************************** THREAD ROUTINES *******************************
- ***********************************************************************************/
-
- /***********************************************************************************
- **
- ** Spawn each thread from the pool of newly created threads (you can change this
- ** thread type to Preemptive, just make sure to change the init_threads routine, too
- */
- void spawn_threads()
- {
- OSErr anError;
- short index;
-
- ThreadBeginCritical();
- for ( index = 0; index < kNumOfPhilosophizers; index++ )
- {
- anError = NewThread (kCooperativeThread,
- philo_actions,
- (void *)&(gPhilosophizer[index]),
- (Size)0,
- kUsePremadeThread, /* don't need the FPU context saved */
- nil,
- &(gPhilosophizer[index].theThread));
-
- if ( anError )
- error("\pError in creating the New Thread (spawn_threads)", anError, kFatal);
- }
- ThreadEndCritical();
- }
-
-
- /***********************************************************************************
- **
- ** Do the think-eat thing kNumberOfIterations times.
- */
- pascal void *philo_actions(void *thisPhilo)
- {
- short index;
-
- for (index = 0; index < kNumberOfIterations; index++ )
- {
- think_for_a_while();
- go_to_eat(thisPhilo);
- pick_up_left_fork(thisPhilo);
- pick_up_right_fork(thisPhilo);
- eat_for_a_while(thisPhilo);
- put_down_right_fork(thisPhilo);
- put_down_left_fork(thisPhilo);
- go_to_think(thisPhilo);
- }
- }
-
-
- /***********************************************************************************
- **
- ** Think for a random amount of time and Yield while thinking
- */
- void think_for_a_while()
- {
- short counter;
- short timeToThink;
-
- #ifndef THINK_C
- GetDateTime((unsigned long *)&qd.randSeed);
- #else
- GetDateTime((unsigned long *)&randSeed);
- #endif
- timeToThink = Random() % kThinkingTimeLimit;
-
- for ( counter = 0; counter < timeToThink; counter++ )
- YieldToAnyThread()
- ;
- }
-
-
- /***********************************************************************************
- **
- ** Take out the checkin_with_footman call to see a nice visual rep of deadlock
- ** you should also do the same with the checkout_with_footman call in go_to_think
- */
- void go_to_eat(philoPtr thisPhilo)
- {
- thisPhilo->current_location = thisPhilo->waiting_location;
-
- checkin_with_footman();
-
- thisPhilo->current_location = thisPhilo->dining_location;
- YieldToAnyThread();
- }
-
-
- /***********************************************************************************
- **
- ** Yield while eating
- */
- void eat_for_a_while(philoPtr thisPhilo)
- {
- short counter, timeToEat = Random() % kEatingTimeLimit;
-
- thisPhilo->current_location = thisPhilo->dining_location;
- for (counter = 0; counter < timeToEat; counter++)
- YieldToAnyThread()
- ;
- }
-
-
- /***********************************************************************************
- **
- ** Take out checkout… call to see deadlock
- */
- void go_to_think(philoPtr thisPhilo)
- {
- checkout_with_footman();
-
- thisPhilo->current_location = thisPhilo->thinking_location;
- thisPhilo->fork_state = kNoForks;
- YieldToAnyThread();
- }
-
-
- /***********************************************************************************
- ******************************* FORK ROUTINES ********************************
- ***********************************************************************************/
-
- /***********************************************************************************
- **
- ** Create the array of simple semaphores (in a global array)
- */
- void create_forks()
- {
- short count;
- OSErr anError;
-
- for ( count = 0; count < kNumOfPhilosophizers; count++ )
- {
- anError = CreateSimpleSemaphore(&gForks[count]);
- if ( anError )
- error("\pProblem creating one of the forks", anError, kFatal);
- }
- }
-
-
- /***********************************************************************************
- **
- ** These next four routines either Get or Release the proper semaphore to
- ** do some eatin'.
- **
- ** Each philosophizer knows what its left fork is (part of its structure), and
- ** its right fork is just the one next to its left-- mod kNumOfPhilosophizers,
- ** of course.
- */
- void pick_up_left_fork(philoPtr thisPhilo)
- {
- OSErr anError;
-
- anError = GetSimpleSemaphore(LEFT_FORK(thisPhilo));
-
- if ( anError )
- error("\pProblem getting a Left Fork", anError, kFatal);
-
- thisPhilo->fork_state = kLeftFork;
- YieldToAnyThread();
- }
-
-
- void pick_up_right_fork(philoPtr thisPhilo)
- {
- OSErr anError;
-
- anError = GetSimpleSemaphore(RIGHT_FORK(thisPhilo));
-
- if ( anError )
- error("\pProblem getting an Right Fork", anError, kFatal);
-
- thisPhilo->fork_state = kBothForks;
- YieldToAnyThread();
- }
-
-
- void put_down_right_fork(philoPtr thisPhilo)
- {
- OSErr anError;
-
- anError = ReleaseSimpleSemaphore(RIGHT_FORK(thisPhilo));
-
- if ( anError )
- error ("\pProblem releasing the Right Fork", anError, kFatal);
-
- thisPhilo->fork_state = kLeftFork;
- YieldToAnyThread();
- }
-
-
- void put_down_left_fork(philoPtr thisPhilo)
- {
- OSErr anError;
-
- anError = ReleaseSimpleSemaphore(LEFT_FORK(thisPhilo));
-
- if ( anError )
- error ("\pProblem releasing the Left Fork", anError, kFatal);
-
- thisPhilo->fork_state = kNoForks;
- YieldToAnyThread();
- }
-
-
- /*ç
- **
- ** Get rid of each of the forks in the global array
- */
- void remove_forks()
- {
- short counter;
- OSErr anError;
-
- for ( counter = 0; counter < kNumOfPhilosophizers; counter++ )
- {
- anError = DeleteSimpleSemaphore(gForks[counter]);
-
- if ( anError )
- error("\pProblem Deleting the Simple semaphore", anError, kFatal);
- }
- }
-
-
- /***********************************************************************************
- ***************************** FOOTMAN ROUTINES *******************************
- ***********************************************************************************/
-
- /***********************************************************************************
- **
- ** Either set up the Array semaphore to let 'em in one at a time (preserving their
- ** order), or init the NumEating.
- */
- void create_footman()
- {
- #ifdef kUsingArraySemaphore
-
- OSErr anError = CreateArraySemaphore(kNumAllowedIn, &gFootman);
-
- if ( anError )
- error ("\pProblem creating the Footman", anError, kFatal);
- #else
-
- gNumEating = 0;
- #endif
- }
-
-
- /***********************************************************************************
- **
- ** Either go for the semaphore (which will Yield until one is available), or
- ** go on through if there's room. If there ain't room, Yield until there is.
- */
- void checkin_with_footman()
- {
- #ifdef kUsingArraySemaphore
-
- OSErr anError = GetArraySemaphore(gFootman);
-
- if ( anError )
- error("\pProblem Checking in with the Footman", anError, kFatal);
- #else
-
- while ( gNumEating == kNumAllowedIn )
- YieldToAnyThread()
- ;
-
- gNumEating++;
- #endif
- }
-
-
- /***********************************************************************************
- **
- ** Release the semaphore, or decrement the NumEating.
- */
- void checkout_with_footman()
- {
- #ifdef kUsingArraySemaphore
-
- OSErr anError = ReleaseArraySemaphore(gFootman);
-
- if ( anError )
- error ("\pProblem Checking out with the Footman", anError, kFatal);
- #else
-
- gNumEating--;
- #endif
- }
-
-
- /***********************************************************************************
- **
- ** Throw out the Array semaphpore
- */
- void retire_footman()
- {
- #ifdef kUsingArraySemaphore
-
- OSErr anError;
-
- gFootman->numberWaiting = 0; /* This makes me uneasy */
-
- anError = DeleteArraySemaphore(gFootman);
- if ( anError )
- error("\pProblem Retiring the Footman", anError, kFatal);
- #endif
- }
-